package mybatis.generator;


import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.IFileCreate;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.FileType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import mybatis.generator.util.GenUtil;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang3.StringUtils;

/**
 * 代码生成器
 */
public class CodeGenerator {

  /**
   * 配置文件 修改后有时打不进target 用静态
   */

  public static final String TABLE_PREFIX = "t_";
  public static final String FIELD_PREFIX = "f_";

  /**
   * 覆盖已存在的文件
   */
  public static final boolean FILE_OVER_WRITE = false;
  /**
   * 生成保存在module目录
   */
  public static final String MODULE_PATH = "paw-portal";
  public static final String OUTPUT_DIR = MODULE_PATH + "/src/main/java";
  public static final String PACKAGE_NAME = "com.paw";
  public static final String MODULE = "portal";
  /**
   * 要生成的表名
   */
  // t_sys_user,t_sys_menu,t_sys_role
  public static final String TABLE_NAMES = "t_sys_user_role";

  public static void main (String[] args) {
    // 代码生成器
    AutoGenerator mpg = new AutoGenerator();

    Configuration config = getConfig();

    String packageName = PACKAGE_NAME;
    String module = MODULE;
//        String inputOutputDir = OUTPUT_DIR;
    String[] tableNames = TABLE_NAMES.split(",");

    // 全局配置
    GlobalConfig globalConfig = new GlobalConfig();
    // 设置主键类型
    globalConfig.setIdType(IdType.ASSIGN_ID);

    // 修改时间类型 java.util.Date
    globalConfig.setDateType(DateType.ONLY_DATE);
    String projectPath = System.getProperty("user.dir");
    String outputDir = OUTPUT_DIR;
    if (isRelativePath(outputDir)) {
      outputDir = projectPath + File.separator + outputDir;
    }
    globalConfig.setOutputDir(outputDir);
    String author = config.getString("author");
    if (StringUtils.isNotBlank(author)) {
      globalConfig.setAuthor(author);
    }
    globalConfig.setOpen(false);
    // 实体属性 Swagger2 注解
    boolean swaggerEnable = config.getBoolean("swagger2", true);
    globalConfig.setSwagger2(swaggerEnable);


    // mapper.xml
    globalConfig.setBaseColumnList(false);
    globalConfig.setBaseResultMap(false);

    // 覆盖文件
    globalConfig.setFileOverride(FILE_OVER_WRITE);

    mpg.setGlobalConfig(globalConfig);

    // 数据源配置
    DataSourceConfig dsc = new DataSourceConfig();
    String datasourceUrl = config.getString("datasource.url");
    dsc.setUrl(datasourceUrl);
    // dsc.setSchemaName("public");
    dsc.setDriverName(config.getString("datasource.driver-class-name"));
    dsc.setUsername(config.getString("datasource.username"));
    dsc.setPassword(config.getString("datasource.password"));
    mpg.setDataSource(dsc);

    // 包配置
    PackageConfig packageConfig = new PackageConfig();

    packageConfig.setModuleName(module);
    packageConfig.setParent(packageName);
    mpg.setPackageInfo(packageConfig);

    // 自定义配置

    // 如果模板引擎是 freemarker
    String templatePath = "/templates/mapper.xml.ftl";
    // 如果模板引擎是 velocity
    // String templatePath = "/templates/mapper.xml.vm";

    // 自定义输出配置
    List<FileOutConfig> focList = new ArrayList<>();
    // 自定义配置会被优先输出
    focList.add(new FileOutConfig(templatePath) {
      @Override
      public String outputFile (TableInfo tableInfo) {
        // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
        return projectPath + "/" + MODULE_PATH + "/src/main/resources/mapper/"
            + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
      }
    });

    // 自定义输出配置
    String modulePath = StringUtils.isNotEmpty(MODULE) ? "/" + module : "";
    String webDir = outputDir + "/pages" + modulePath + "/";
    String outPath = outputDir;
    // 自定义配置会被优先输出
    String basePackagePath = packageName.replace(".", "/") + "/" + MODULE+"/";
    String requestTemplatePath = "/templates/request.java.ftl";
    focList.add(new FileOutConfig(requestTemplatePath) {
      @Override
      public String outputFile (TableInfo tableInfo) {
        return outPath + "/" + basePackagePath+ "/request/dto/" + tableInfo.getEntityName()+"RequestDto.java";
      }
    });

    String responseTemplatePath = "/templates/response.java.ftl";
    focList.add(new FileOutConfig(responseTemplatePath) {
      @Override
      public String outputFile (TableInfo tableInfo) {
        return outPath + "/" + basePackagePath+ "/response/dto/" + tableInfo.getEntityName()+"ResponseDto.java";
      }
    });

    String enumTemplatePath = "/templates/enums.java.ftl";
    focList.add(new FileOutConfig(enumTemplatePath) {
      @Override
      public String outputFile (TableInfo tableInfo) {
        return outPath + "/" + basePackagePath+ "/enums/" + tableInfo.getEntityName()+"Enums.java";
      }
    });


//        mpg.setCfg(cfg);

    // 自定义属性
    boolean securityEnable = config.getBoolean("security-enable", true);
    InjectionConfig injectionConfig = new InjectionConfig() {
      //自定义属性注入:abc
      //在.ftl(或者是.vm)模板中，通过${cfg.abc}获取属性
      @Override
      public void initMap () {
        Map<String, Object> map = new HashMap<>();
//                map.put("securityEnable", genurityEnable);
        GenUtil genUtil = new GenUtil();
        // 使用 ${cfg.genUtil.lowerFirst(table.entityName)}
        map.put("genUtil", genUtil);

        ArrayList<String> skipFields = new ArrayList<>();
        skipFields.add("delFlag");
//        Arrays.asList("delFlag","createTime","createBy","updateTime","updateBy");
        map.put("skipFields",skipFields);
        String packageName = PACKAGE_NAME+StringPool.DOT+MODULE;
        map.put("packageName",packageName);
        map.put("requestPackage",packageName+StringPool.DOT+"request.dto");
        map.put("responsePackage",packageName+StringPool.DOT+"response.dto");
        map.put("enumPackage",packageName+StringPool.DOT+"enums");
        map.put("commonEnum","com.paw.common.enums.ICommonEnum");

        this.setMap(map);
      }
    };

    injectionConfig.setFileOutConfigList(focList);

    //  是否覆盖文件
    injectionConfig.setFileCreate(new IFileCreate() {
      @Override
      public boolean isCreate (ConfigBuilder configBuilder, FileType fileType, String filePath) {
        // 判断自定义文件夹是否需要创建
        File file = new File(filePath);
        boolean exist = file.exists();
        if (!exist) {
          file.getParentFile().mkdirs();
        }
        if (FILE_OVER_WRITE) {
          return true;
        }
        return !exist;
      }
    });

    //配置自定义属性注入
    mpg.setCfg(injectionConfig);

    // 配置模板
    TemplateConfig templateConfig = new TemplateConfig();

    // 配置自定义输出模板
    //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
    // templateConfig.setEntity("templates/entity2.java");
    // templateConfig.setService();
    // templateConfig.setController();

//        templateConfig.setXml("mapper");
    mpg.setTemplate(templateConfig);

    // 策略配置
    StrategyConfig strategy = new StrategyConfig();
    strategy.setNaming(NamingStrategy.underline_to_camel);
    strategy.setColumnNaming(NamingStrategy.underline_to_camel);
    strategy.setEntityLombokModel(true);
    strategy.setRestControllerStyle(true);
    strategy.setChainModel(true);

    // 公共父实体类
    String superEntityClass = config.getString("super-entity-class");
    if (StringUtils.isNotBlank(superEntityClass)) {
      strategy.setSuperEntityClass(superEntityClass);
    }
    // 公共父mapper
    String superMapperClass = config.getString("super-mapper-class");
    if (StringUtils.isNotBlank(superMapperClass)) {
      strategy.setSuperMapperClass(superMapperClass);
    }
    // 公共父mapper
    String superServiceClass = config.getString("super-service-class");
    if (StringUtils.isNotBlank(superServiceClass)) {
      strategy.setSuperServiceClass(superServiceClass);
    }
    // 公共父类
    String superControllerClass = config.getString("super-controller-class");
    if (StringUtils.isNotBlank(superControllerClass)) {
      strategy.setSuperControllerClass(superControllerClass);
    }

    // 写于父类中的公共字段
//        strategy.setSuperEntityColumns("id");
    strategy.setInclude(tableNames);
//        strategy.setControllerMappingHyphenStyle(true);
    strategy.setCapitalMode(true);
    strategy.setLogicDeleteFieldName("del_flag");
    List<TableFill> fillList = new ArrayList<>();
    TableFill createTimeFill = new TableFill("f_create_time", FieldFill.INSERT);
    TableFill updateTimeFill = new TableFill("f_update_time", FieldFill.INSERT_UPDATE);
    TableFill creatorFill = new TableFill("f_create_by", FieldFill.INSERT);
    TableFill modifierFill = new TableFill("f_update_by", FieldFill.UPDATE);
    fillList.add(createTimeFill);
    fillList.add(updateTimeFill);
    fillList.add(creatorFill);
    fillList.add(modifierFill);

    strategy.setTableFillList(fillList);

    // 实体表字段注解 isEntityTableFieldAnnotationEnable
    strategy.setEntityTableFieldAnnotationEnable(true);
    strategy.setTablePrefix(TABLE_PREFIX);
    strategy.setFieldPrefix(FIELD_PREFIX);
    mpg.setStrategy(strategy);

    String templateEngine = config.getString("template-engine", "").trim();
    mpg.setTemplateEngine(new FreemarkerTemplateEngine());
    mpg.execute();
  }

  /**
   * 获取配置信息
   */
  public static Configuration getConfig () {
    try {
      return new PropertiesConfiguration("generator.properties");
    } catch (ConfigurationException e) {
      throw new RuntimeException("获取配置文件失败，", e);
    }
  }

  /**
   * 相对路径
   *
   * @param path
   * @return
   */
  public static boolean isRelativePath (String path) {
    if (StringUtils.isBlank(path)) {
      return true;
    }
    if (path.contains(":\\") || path.contains(":/")) {
      return false;
    }
    // linux / 开始为根目录
    if (path.startsWith("/") && "/".equals(File.separator)) {
      return false;
    }

    return true;
  }

  public static String firstToLowerCase (String name) {
    if (StringUtils.isNotEmpty(name)) {
      name = name.substring(0, 1).toLowerCase() + name.substring(1);
    }
    return name;
  }
}
